#ifndef DYNOBJ_HPP
#define DYNOBJ_HPP

/*  动态对象生成示例

class DemoA
{
public:
    virtual void test() { printf("DemoA\n"); }
    DEF_DYNOBJ(DemoA)
};

IMP_DYNOBJ(DemoA)

.....

DemoA* a = (DemoA*)create_dynobj("DemoA");


*/

/* 原理
利用静态对象的自动加载功能（程序启动时），注册对象的信息（名称、创建对象的函数）
*/


namespace dynobj
{

struct RuntimeClass
{
    const char* name;      //类名称
    void* (*create)(void); //创建类的对象
};

void* create_dynobj(const char* class_name);
bool find_class(const char* class_name);
void enum_class(void (*call)(void* ctx, const char* class_name), void* ctx);

namespace internal
{
    class ClassReg
    {
    public:
        ClassReg(const RuntimeClass* rc);
    };

    typedef void* (*create_dynobject_fn)(void);
}


//放到类内部
#define DEF_DYNOBJ(name) \
public: \
    static name * create_object(void); \
    static const dynobj::RuntimeClass Class##name; \
    virtual const dynobj::RuntimeClass* get_runtimeclass() const;

//放到类的实现文件中
#define IMP_DYNOBJ(name) \
name * name::create_object() { return new name; } \
const dynobj::RuntimeClass name::Class##name = {#name, (dynobj::internal::create_dynobject_fn)&name::create_object}; \
const dynobj::RuntimeClass* name::get_runtimeclass() const { return &name::Class##name; } \
static const dynobj::internal::ClassReg reg_Class##name(&name::Class##name);


#define DEF_CLASS_DYNOBJ(name) \
    class T##name : public name \
    { \
    public: \
        static name * create_object(void); \
        static const dynobj::RuntimeClass Class##name; \
        virtual const dynobj::RuntimeClass* get_runtimeclass() const; \
    }; 

#define IMP_CLASS_DYNOBJ(name) \
    name * T##name::create_object() { return new name; } \
    const dynobj::RuntimeClass T##name::Class##name = {#name, (dynobj::internal::create_dynobject_fn)&T##name::create_object}; \
    const dynobj::RuntimeClass* T##name::get_runtimeclass() const { return &T##name::Class##name; } \
    static const dynobj::internal::ClassReg reg_Class##name(&T##name::Class##name);

}

#endif //DYNOBJ_HPP
